package com.atguigu.yygh.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.yygh.common.exception.YyghException;
import com.atguigu.yygh.enums.OrderStatusEnum;
import com.atguigu.yygh.enums.PaymentStatusEnum;
import com.atguigu.yygh.enums.PaymentTypeEnum;
import com.atguigu.yygh.enums.RefundStatusEnum;
import com.atguigu.yygh.model.order.OrderInfo;
import com.atguigu.yygh.model.order.PaymentInfo;
import com.atguigu.yygh.model.order.RefundInfo;
import com.atguigu.yygh.order.prop.WeiPayProperties;
import com.atguigu.yygh.order.service.OrderInfoService;
import com.atguigu.yygh.order.service.PaymentService;
import com.atguigu.yygh.order.service.RefundInfoService;
import com.atguigu.yygh.order.service.WeiPayService;
import com.atguigu.yygh.order.utils.HttpClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.wxpay.sdk.WXPayUtil;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author mgx
 * @version 1.0
 * @description: TODO
 * @date 2022/9/8 18:19
 */
@Service
public class WeiPayServiceImpl implements WeiPayService {

    @Autowired
    private OrderInfoService orderInfoService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private WeiPayProperties weiPayProperties;

    @Autowired
    private RefundInfoService refundInfoService;


    @Override
    public String createNative(Long orderId) {
        // 1.根据订单id去数据库中查询订单信息
        OrderInfo orderInfo = orderInfoService.getById(orderId);
        // 2.把支付记录保存到数据库中
        paymentService.savePaymentInfo(orderInfo, PaymentTypeEnum.WEIXIN.getStatus());
        // 3.请求微信支付服务器获取二维码相关信息url
        HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder"); // 请求微信服务器地址
        // 创建一个paramMap
        Map<String , String> paramMap = new HashMap<>();
        // 放入参数
        paramMap.put("appid", weiPayProperties.getAppid());
        paramMap.put("mch_id", weiPayProperties.getPartner());
        paramMap.put("nonce_str", WXPayUtil.generateNonceStr()); // 必须使用微信的工具类随机生成字符串【算法】
        Date reserveDate = orderInfo.getReserveDate();
        String reserveDateString = new DateTime(reserveDate).toString("yyyy/MM/dd");
        String body = reserveDateString + "就诊"+ orderInfo.getDepname();
        paramMap.put("body", body);
        paramMap.put("out_trade_no", orderInfo.getOutTradeNo());
        paramMap.put("total_fee", "1");// 测试，分为单位
        paramMap.put("spbill_create_ip", "127.0.0.1"); // 终端ip随便给一个
        paramMap.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify"); // 通知的公网ip，随便给一个
        paramMap.put("trade_type", "NATIVE");


        try {
            String xmlParam = WXPayUtil.generateSignedXml(paramMap, weiPayProperties.getPartnerKey());
            httpClient.setXmlParam(xmlParam);// 设置参数
            httpClient.setHttps(true); // 设置支持https协议
            httpClient.post();
            String xmlResult = httpClient.getContent(); // 微信支付服务器返回的xml字符串
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xmlResult); // 把xml结果转化为map
            // System.out.println(resultMap);
            // 4.返回url
            return resultMap.get("code_url");
        } catch (Exception e) {
            return "";
        }
    }

    @Override
    public Map<String, String> queryStatus(Long orderId) {
        // 根据orderId查询订单信息
        OrderInfo orderInfo = orderInfoService.getById(orderId);
        // 向微信服务器发送查询订单的支付状态
        HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("appid", weiPayProperties.getAppid());
        paramMap.put("mch_id", weiPayProperties.getPartner());
        paramMap.put("out_trade_no", orderInfo.getOutTradeNo());  // 或者设置微信订单号
        paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
        try {
            String xmlParam = WXPayUtil.generateSignedXml(paramMap, weiPayProperties.getPartnerKey());
            httpClient.setXmlParam(xmlParam);
            httpClient.setHttps(true);
            httpClient.post();
            String content = httpClient.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
            return resultMap;
        } catch (Exception e) {
            return null;
        }

    }

    @Transactional
    @Override
    public void paymentSuccess(Long orderId, Map<String, String> map) {
        // 1.更新order表支付状态
        OrderInfo orderInfo = orderInfoService.getById(orderId);
        orderInfo.setOrderStatus(OrderStatusEnum.PAID.getStatus());
        orderInfoService.updateById(orderInfo);
        // 2.更新付款表的信息
        UpdateWrapper<PaymentInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("out_trade_no", orderInfo.getOutTradeNo()); // 查询条件 where
        updateWrapper.set("trade_no", map.get("transaction_id")); // 更新微信端的支付订单号
        updateWrapper.set("callback_time", new Date());
        updateWrapper.set("callback_content", JSONObject.toJSONString(map));
        updateWrapper.set("payment_status", PaymentStatusEnum.PAID.getStatus());
        paymentService.update(updateWrapper);
    }

    @Override
    public boolean refund(Long orderId) { // 执行微信退款
        // 查询支付记录
        QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", orderId);
        PaymentInfo paymentInfo = paymentService.getOne(queryWrapper);
        // 保存退款记录
        RefundInfo refundInfo = refundInfoService.saveRefundInfo(paymentInfo);
        // 已经退款
        if(refundInfo.getRefundStatus().intValue() == RefundStatusEnum.REFUND.getStatus().intValue()) {
            return true;
        }
        // 请求微信服务器 -- 执行微信退款流程
        HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/secapi/pay/refund");
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("appid", weiPayProperties.getAppid());
        paramMap.put("mch_id", weiPayProperties.getPartner());
        paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
        paramMap.put("transaction_id", paymentInfo.getTradeNo()); // 此处对应的是微信的支付订单号【微信服务器给的】
        paramMap.put("total_fee", "1"); // 总金额，应该是amount，此处做测试用
        paramMap.put("refund_fee", "1"); // 退款金额
        paramMap.put("out_refund_no", "tk" + paymentInfo.getOutTradeNo()); // 商家退款订单号


        try {
            String paramXmlString = WXPayUtil.generateSignedXml(paramMap, weiPayProperties.getPartnerKey());
            httpClient.setXmlParam(paramXmlString);
            httpClient.setHttps(true);
            httpClient.setCert(true); // 微信退款需要双向证书
            httpClient.setCertPassword(weiPayProperties.getPartner()); // 双向证书的密码是商户号
            httpClient.post();
            String content = httpClient.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
            // 判断是否成功退款
            if("SUCCESS".equals(resultMap.get("result_code"))) {
                // 设置微信退款单号-- 微信服务器给我们返回的
                refundInfo.setTradeNo(resultMap.get("refund_id"));
                refundInfo.setRefundStatus(RefundStatusEnum.REFUND.getStatus());
                refundInfo.setCallbackTime(new Date());
                refundInfo.setCallbackContent(JSONObject.toJSONString(resultMap));
                refundInfoService.updateById(refundInfo);
                return true;
            }
            return false;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
